﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Caching;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Services;
using ControleRepresentante.Logic.ImpostoHandlers;
using ControleRepresentante.Logic.Models;
using ControleRepresentante.Logic.Repositories;
using ControleRepresentante.Logic.Statistics;
using SelectPdf;
using WebSite.Controllers;
using WebSite.Controllers.PrintTemplates;
using WebSite.Services.Contracts;
using WebSite.ViewModels;
using ControllerBase = System.Web.Mvc.ControllerBase;

namespace WebSite.Services
{
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    public class SearchService : WebServiceBase
    {
        [WebMethod(EnableSession = true)]
        public List<ClienteContract> GetClientes()
        {
            return GetClientes(RepositoryProvider);
        }

        [WebMethod(EnableSession = true)]
        public List<VendedorContract> GetVendedores()
        {
            return GetVendedores(RepositoryProvider);
        }

        [WebMethod(EnableSession = true)]
        public List<TransportadoraContract> GetTransportadoras()
        {
            return GetTransportadoras(RepositoryProvider);
        }

        [WebMethod(EnableSession = true)]
        public List<FabricaContract> GetFabricas()
        {
            return RepositoryProvider.GetRepository<IFabricaRepository>().GetModelNames()
                .Select(x => new FabricaContract
                {
                    Id = x.Key,
                    Nome = x.Value
                })
                .ToList();
        }

        [WebMethod(EnableSession = true)]
        public List<PedidoInfoContract> GetLastPedidos(string vendedorId, string clienteId, string fabricaId, string transportadoraId, int count)
        {
            Guid? vendedorIdFinal = String.IsNullOrWhiteSpace(vendedorId) ? (Guid?) null : Guid.Parse(vendedorId);
            Guid? clienteIdFinal = String.IsNullOrWhiteSpace(clienteId) ? (Guid?)null : Guid.Parse(clienteId);
            Guid? fabricaIdFinal = String.IsNullOrWhiteSpace(fabricaId) ? (Guid?)null : Guid.Parse(fabricaId);
            Guid? transportadoraIdFinal = String.IsNullOrWhiteSpace(transportadoraId) ? (Guid?)null : Guid.Parse(transportadoraId);
            IEnumerable<Pedido> pedidos = RepositoryProvider.GetRepository<IPedidoRepository>(new ImpostoProvider())
                                                            .GetModels(vendedorIdFinal, clienteIdFinal, fabricaIdFinal,
                                                                       transportadoraIdFinal, count);
            return pedidos.Select(pedido => new PedidoInfoContract
                {
                    Id = pedido.Id.ToString(),
                    Numero = pedido.Numero,
                    Data = pedido.Data,
                    Total = pedido.TotalLiquido,
                    ClienteId = pedido.Cliente.Id.ToString(),
                    FabricaId = pedido.Fabrica.Id.ToString(),
                    TransportadoraId = pedido.Transportadora.Id.ToString(),
                    VendedorId = pedido.Vendedor.Id.ToString(),
                    Produtos = pedido.Produtos.Select(produto => new ProdutoContract
                        {
                            Codigo = produto.Codigo,
                            Descricao = produto.Descricao,
                            PrecoUnitario = produto.PrecoUnitario,
                            Quantidade = produto.Quantidade
                        }).ToArray()
                })
                .ToList();
        }

        private class MyHttpContextBase : HttpContextBase
        {
            private readonly IDictionary m_Items = new Dictionary<object, object>();
            private readonly Cache m_Cache = new Cache();
            private readonly MyHttpRequest m_MyHttpRequest = new MyHttpRequest();
            private readonly MyHttpResponseBase m_MyHttpResponseBase = new MyHttpResponseBase();

            public override HttpRequestBase Request
            {
                get { return m_MyHttpRequest; }
            }

            public override IDictionary Items
            {
                get { return m_Items; }
            }

            public override Cache Cache
            {
                get { return m_Cache; }
            }

            public override HttpResponseBase Response
            {
                get { return m_MyHttpResponseBase; }
            }

            private class MyHttpResponseBase : HttpResponseBase
            {
                public override string ApplyAppPathModifier(string virtualPath)
                {
                    return "http://controlerepresentante.com.br" + virtualPath;
                }
            }

            private class MyHttpRequest : HttpRequestBase
            {
                private readonly NameValueCollection m_NameValueCollection = new NameValueCollection();

                public override bool IsLocal
                {
                    get { return true; }
                }

                public override string ApplicationPath
                {
                    get { return "/"; }
                }

                public override NameValueCollection ServerVariables
                {
                    get { return m_NameValueCollection; }
                }
            }
        }

        private class MyController : ControllerBase
        {
            protected override void ExecuteCore()
            {
            }
        }

        [WebMethod(EnableSession = true)]
        public string GetPedidoPrintHtml(string pedidoId)
        {
            IPedidoRepository pedidoRepository = RepositoryProvider.GetRepository<IPedidoRepository>(new ImpostoProvider());
            Pedido pedido = pedidoRepository.GetModelById(Guid.Parse(pedidoId));
            Representante representante = pedidoRepository.GetRepresentante();
            IPrintTemplate printTemplate = new PrintTemplateSelector().GetPrintTemplate(representante, pedido);
            string vendedorPrint = PedidoController.GetVendedorPrint(representante, pedido);
            PedidoPrintViewModel pedidoPrintViewModel = new PedidoPrintViewModel(representante.RepresentanteInfo, pedido, printTemplate.GetNumero(pedido), vendedorPrint);
            RouteData routeData = new RouteData();
            routeData.Values.Add("controller", "Pedido");
            ControllerContext controllerContext = new ControllerContext(new MyHttpContextBase(), routeData, new MyController());
            IView view = new RazorView(controllerContext, "~/Views/Pedido/" + printTemplate.ViewName + ".cshtml",
                          "~/Views/Pedido/_PrintLayout.cshtml", false, new string[0], null);
            controllerContext.Controller.ViewData.Model = pedidoPrintViewModel;
            string result;

            using (StringWriter stringWriter = new StringWriter())
            {
                var ctx = new ViewContext(controllerContext, view,
                                            controllerContext.Controller.ViewData,
                                            controllerContext.Controller.TempData,
                                            stringWriter);
                view.Render(ctx, stringWriter);
                result = stringWriter.ToString();
            }

            return result;
        }

        [WebMethod(EnableSession = true)]
        public string GetPedidoPrintPdf(string pedidoId)
        {
            string pedidoPrintHtml = GetPedidoPrintHtml(pedidoId);
            HtmlToPdf converter = new HtmlToPdf();
            PdfDocument doc = converter.ConvertHtmlString(pedidoPrintHtml);
            using (MemoryStream memoryStream = new MemoryStream())
            {
                doc.Save(memoryStream);
                doc.Close();
                byte[] bytes = memoryStream.ToArray();
                return Convert.ToBase64String(bytes);
            }
        }

        [WebMethod(EnableSession = true)]
        public ClienteInfoContract GetClienteInfo(string clienteId)
        {
            return CreateDetailsHolderContract<Cliente, IClienteRepository, ClienteInfoContract>(
                clienteId, (contract, model) =>
                    {
                        contract.CNPJ = model.CNPJ;
                        contract.InscricaoEstadual = model.InscricaoEstadual;
                        contract.NomeFantasia = model.NomeFantasia;
                    });
        }

        [WebMethod(EnableSession = true)]
        public FabricaInfoContract GetFabricaInfo(string fabricaId)
        {
            return CreateDetailsHolderContract<Fabrica, IFabricaRepository, FabricaInfoContract>(
                fabricaId, (contract, model) =>
                {
                    contract.CNPJ = model.CNPJ;
                    contract.InscricaoEstadual = model.InscricaoEstadual;
                });
        }

        [WebMethod(EnableSession = true)]
        public VendedorInfoContract GetVendedorInfo(string vendedorId)
        {
            return CreateDetailsHolderContract<Vendedor, IVendedorRepository, VendedorInfoContract>(
                vendedorId, (contract, model) =>
                {
                    contract.CPF = model.CPF;
                    contract.Identidade = model.Identidade;
                });
        }

        [WebMethod(EnableSession = true)]
        public TransportadoraInfoContract GetTransportadoraInfo(string transportadoraId)
        {
            return CreateDetailsHolderContract<Transportadora, ITransportadoraRepository, TransportadoraInfoContract>(
                transportadoraId, (contract, model) => {});
        }

        private TContract CreateDetailsHolderContract<TModel, TRepository, TContract>(string id, Action<TContract, TModel> action)
            where TContract : DetailsHolderContract
            where TModel : DetailsHolder
            where TRepository : IDetailsHolderRepository<TModel, StatisticsBase>
        {
            TRepository repository = RepositoryProvider.GetRepository<TRepository>();
            TModel detailsHolder = repository.GetModelById(Guid.Parse(id));

            TContract detailsHolderContract = (TContract)Activator.CreateInstance(typeof(TContract));
            detailsHolderContract.Id = detailsHolder.Id.ToString();
            detailsHolderContract.Telefone = detailsHolder.ContatoTelefone;
            detailsHolderContract.Fax = detailsHolder.ContatoFax;
            detailsHolderContract.Email = detailsHolder.ContatoEmail;
            detailsHolderContract.Celular = detailsHolder.ContatoCelular;
            detailsHolderContract.Rua = detailsHolder.EnderecoRua;
            detailsHolderContract.Numero = detailsHolder.EnderecoNumero;
            detailsHolderContract.Complemento = detailsHolder.EnderecoComplemento;
            detailsHolderContract.Bairro = detailsHolder.EnderecoBairro;
            detailsHolderContract.CEP = detailsHolder.EnderecoCEP;
            detailsHolderContract.Cidade = detailsHolder.EnderecoCidade;
            detailsHolderContract.Estado = detailsHolder.EnderecoEstado;

            action(detailsHolderContract, detailsHolder);

            return detailsHolderContract;
        }

        internal static List<ClienteContract> GetClientes(IRepositoryProvider repositoryProvider)
        {
            StatisticsBase statistics;
            return repositoryProvider.GetRepository<IClienteRepository>().GetModels(out statistics)
                                     .Select(x => new ClienteContract
                                     {
                                         CodigoJolitex = x.ClienteJolitex == null ? null : x.ClienteJolitex.Codigo,
                                         RazaoSocial = x.RazaoSocial,
                                         Id = x.Id,
                                         VendedorId = x.Vendedor == null ? (Guid?)null : x.Vendedor.Id
                                     })
                                     .ToList();
        }

        internal static List<VendedorContract> GetVendedores(IRepositoryProvider repositoryProvider)
        {
            return repositoryProvider.GetRepository<IVendedorRepository>().GetModelNames()
                                     .Select(x => new VendedorContract
                                     {
                                         Id = x.Key,
                                         Nome = x.Value
                                     })
                                     .ToList();
        }

        internal static List<TransportadoraContract> GetTransportadoras(IRepositoryProvider repositoryProvider)
        {
            StatisticsBase statistics;
            return repositoryProvider.GetRepository<ITransportadoraRepository>().GetModels(out statistics)
                                     .Select(x => new TransportadoraContract
                                     {
                                         Id = x.Id,
                                         Nome = x.Nome,
                                         CodigoJolitex =
                                             x.TransportadoraJolitex == null ? null : x.TransportadoraJolitex.Codigo
                                     })
                                     .ToList();
        }
    }
}